# 作者： 李泉志
# 2025年01月09日15时51分秒
# 2947029073@qq.com

"""
10 单例
目标
• 单例设计模式
• __new__ 方法
• Python 中的单例

01. 单例设计模式
• 设计模式
    – 设计模式是前人工作的总结和提炼，通常，被人们广泛流传的设计模式都是针对某一特定问题的成熟的解决方案
    – 使用设计模式是为了可重用代码、让代码更容易被他人理解、保证可扩展性好，代码可靠性好
• 单例设计模式
    – 目的 —— 让类创建的对象，在系统中只有唯一的一个实例
    – 每一次执行 类名() 返回的对象，内存地址是相同的
单例设计模式的应用场景
• 音乐播放对象
• 回收站对象
• 打印机对象

02. __new__ 方法
• 使用 类名() 创建对象时，Python的解释器首先会调用 __new__ 方法为对象分配空间
• __new__ 是一个由 object 基类提供的内置的静态方法，主要作用有两个：
    – 1) 在内存中为对象分配空间
    – 2) 返回对象的引用
• Python 的解释器获得对象的引用后，将引用作为第一个参数，传递给__init__ 方法
重写 __new__ 方法的代码非常固定！
• 重写 __new__ 方法 一定要 return super().__new__(cls)
    –否则Python的解释器得不到分配了空间的对象引用，就不会调用对象的初始化方法
    –注意：__new__ 是一个静态方法，在调用时需要主动传递 cls 参数

只执行一次初始化工作：
• 在每次使用 类名() 创建对象时，Python的解释器都会自动调用两个方法：
    – __new__ 分配空间
    – __init__ 对象初始化
• 在上一小节对 __new__ 方法改造之后，每次都会得到第一次被创建对象的引用
• 但是：初始化方法还会被再次调用
解决办法
1 定义一个类属性 init_flag 标记是否执行过初始化动作，初始值为False
2 在 __init__ 方法中，判断init_flag，如果为False就执行初始化动作
3 然后将init_flag设置为True
4 这样，再次自动调用 __init__ 方法时，初始化动作就不会被再次执行了
"""


class MusicPlayer:
    instance = None  # 用来保存对象

    def __new__(cls, *args, **kwargs):
        # 1、创建对象，分配空间
        if cls.instance is None:
            cls.instance = super().__new__(cls)
        return cls.instance

    def __init__(self, name):
        self.name = name


if __name__ == '__main__':
    # 实际就一个对象
    player1 = MusicPlayer(3)
    player2 = MusicPlayer(2)
    print(id(player1))
    print(id(player2))
    print(player1.name)
    print(player2.name)
